package ansible

import (
	"context"
	"fmt"
	"io"
)

// Ansible 表示 Ansible 命令执行器
type Ansible struct {
	config    *Config
	inventory interface{}
	hostList  []string
	extraVars map[string]string
	args      []string
	executor  Executor
}

// String 返回 Ansible 实例的字符串表示
func (a *Ansible) String() string {
	return fmt.Sprintf("Ansible{config: %+v, hosts: %v}", a.config, a.hostList)
}

// WorkDirectory 设置工作目录
func (a *Ansible) WorkDirectory(dir string) *Ansible {
	a.config.WorkDirectory = dir
	return a
}

// RequestPty 启用 PTY 模式
func (a *Ansible) RequestPty() *Ansible {
	a.config.EnablePTY = true
	return a
}

// RunWithModule 执行指定的 Ansible 模块
func (a *Ansible) RunWithModule(module string, moduleArgs ...string) ([]byte, []byte, error) {
	// 构建命令参数
	args, err := BuildCommand(a.inventory, a.hostList, module, moduleArgs, a.extraVars)
	if err != nil {
		return nil, nil, err
	}

	// 添加额外参数
	args = append(args, a.args...)

	// 执行命令
	result, err := a.executor.Execute(a.config.Context, a.config, args)
	if err != nil {
		return result.Stdout, result.Stderr, err
	}

	return result.Stdout, result.Stderr, nil
}

// RunWithModuleParsed 执行模块并解析结果
func (a *Ansible) RunWithModuleParsed(module string, moduleArgs ...string) (*AnsibleResult, error) {
	stdout, stderr, err := a.RunWithModule(module, moduleArgs...)
	if err != nil {
		// 即使有错误，也尝试解析结果
		parser := NewResultParser(a.config.OutputFormat)
		if result, parseErr := parser.ParseCommandResult(stdout, stderr); parseErr == nil {
			return result, err
		}
		return nil, err
	}

	parser := NewResultParser(a.config.OutputFormat)
	return parser.ParseCommandResult(stdout, stderr)
}

// SetArgs 设置额外的命令行参数
func (a *Ansible) SetArgs(args ...string) *Ansible {
	a.args = append(a.args, args...)
	return a
}

// Shell 执行 shell 模块
func (a *Ansible) Shell(moduleArgs string) ([]byte, []byte, error) {
	return a.RunWithModule("shell", moduleArgs)
}

// Script 执行 script 模块
func (a *Ansible) Script(moduleArgs string) ([]byte, []byte, error) {
	return a.RunWithModule("script", moduleArgs)
}

// Command 执行 command 模块
func (a *Ansible) Command(moduleArgs string) ([]byte, []byte, error) {
	return a.RunWithModule("command", moduleArgs)
}

// Ping 执行 ping 模块
func (a *Ansible) Ping() ([]byte, []byte, error) {
	return a.RunWithModule("ping")
}

// SetAdditionalVar 设置额外变量
func (a *Ansible) SetAdditionalVar(k, v string) *Ansible {
	if a.extraVars == nil {
		a.extraVars = make(map[string]string)
	}
	a.extraVars[k] = v
	return a
}

// SetAdditionalVars 批量设置额外变量
func (a *Ansible) SetAdditionalVars(vars map[string]string) *Ansible {
	for k, v := range vars {
		a.SetAdditionalVar(k, v)
	}
	return a
}

// SetEnv 设置环境变量
func (a *Ansible) SetEnv(k, v string) *Ansible {
	a.config.SetEnv(k, v)
	return a
}

// SetEnvs 批量设置环境变量
func (a *Ansible) SetEnvs(envs map[string]string) *Ansible {
	a.config.SetEnvs(envs)
	return a
}

// SetOutJson 设置 JSON 输出格式
func (a *Ansible) SetOutJson() *Ansible {
	a.config.WithOutputFormat(OutputFormatJSON)
	return a
}

// ForceColor 强制启用彩色输出
func (a *Ansible) ForceColor() *Ansible {
	a.config.WithForceColor(true)
	return a
}

// CloseWarnings 关闭警告信息
func (a *Ansible) CloseWarnings() *Ansible {
	a.config.WithSuppressWarnings(true)
	return a
}

// SetStdout 设置标准输出
func (a *Ansible) SetStdout(w io.Writer) *Ansible {
	if executor, ok := a.executor.(*DefaultExecutor); ok {
		executor.WithStdout(w)
	}
	return a
}

// SetStderr 设置标准错误输出
func (a *Ansible) SetStderr(w io.Writer) *Ansible {
	if executor, ok := a.executor.(*DefaultExecutor); ok {
		executor.WithStderr(w)
	}
	return a
}

// SetStdin 设置标准输入
func (a *Ansible) SetStdin(r io.Reader) *Ansible {
	if executor, ok := a.executor.(*DefaultExecutor); ok {
		executor.WithStdin(r)
	}
	return a
}

// NewAnsible 创建新的 Ansible 实例
func NewAnsible(binPath string, inventory interface{}, hosts []string, ctx context.Context) *Ansible {
	if binPath == "" {
		binPath = "ansible"
	}
	if len(hosts) == 0 || hosts == nil {
		hosts = []string{"localhost"}
	}
	if ctx == nil {
		ctx = context.Background()
	}

	config := DefaultConfig().
		WithBinPath(binPath).
		WithContext(ctx)

	return &Ansible{
		config:    config,
		inventory: inventory,
		hostList:  hosts,
		extraVars: make(map[string]string),
		args:      make([]string, 0),
		executor:  NewDefaultExecutor(),
	}
}
